package cn.mw.cmdb.processor;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.mw.cmdb.entity.*;
import cn.mw.cmdb.param.InstanceSearchParam;
import cn.mw.cmdb.param.TableSearchParam;
import cn.mw.cmdb.service.impl.CmdbServiceManage;
import cn.mw.cmdb.service.impl.InstanceServiceImpl;
import cn.mw.cmdb.service.impl.ModelPropertyServiceImpl;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.cmdb.viewProcessor.RelateDataViewProcessor;
import cn.mw.cmdb.viewProcessor.ViewProcessorManage;
import cn.mw.components.mongodb.entity.CriteriaOpsType;
import cn.mw.components.mongodb.entity.SubCondition;
import cn.mw.microMonitorCommon.api.common.Constants;
import cn.mw.microMonitorCommon.entity.cmdb.RelatedDataType;
import cn.mw.microMonitorCommon.entity.cmdb.TableHeaderItem;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.mw.cmdb.util.CMDBTool.CMDBDefaultIdKey;
import static cn.mw.cmdb.util.CMDBTool.CMDBDefaultIdName;
import static cn.mw.microMonitorCommon.entity.cmdb.TableHeaderItem.flexNum;

@Slf4j
public class TableProcessorCommonInstance implements TableDataProccessor {
    public static final String SEQ = "seq";
    public static final String offlineKey = "离线";

    private static final String SEQName = "序号";

    private CmdbServiceManage cmdbServiceManage;

    private TableSearchParam tableDataParam;

    private InstanceSearchParam instanceSearchParam;

    private List<String> tableHeaderSort;

    public TableProcessorCommonInstance(CmdbServiceManage cmdbServiceManage, TableSearchParam tableDataParam,
                                        InstanceSearchParam instanceSearchParam, List<String> tableHeaderSort) {
        this.cmdbServiceManage = cmdbServiceManage;
        this.tableDataParam = tableDataParam;
        this.instanceSearchParam = instanceSearchParam;
        this.tableHeaderSort = tableHeaderSort;
    }

    @Override
    public List genData(TableDataProcessorContext context) throws Exception {
        long time1 = System.currentTimeMillis();
        InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
        List<InstanceInfoExtend> instanceInfos = new ArrayList<>();
        String[] assetStateQuery = null;
        // 自定义分类场景，状态节点 id由上级id+资产状态组成 id由属性名:属性值拼接而成
        if (!Strings.isNullOrEmpty(tableDataParam.getId()) && tableDataParam.getId().contains(Constants.ID_SPLIT)) {
            assetStateQuery = tableDataParam.getId().split(Constants.ID_SPLIT)[1].split(Constants.PROPERTY_SPLIT);
            tableDataParam.setId(tableDataParam.getId().split(Constants.ID_SPLIT)[0]);
        }
        if (null == instanceSearchParam) {
            instanceSearchParam = new InstanceSearchParam();
            if (!Strings.isNullOrEmpty(tableDataParam.getId())) {
                SubCondition subCondition = new SubCondition(CriteriaOpsType.is.name(), tableDataParam.getId());
                instanceSearchParam.addSubCondition(CMDBTool.getFieldName(InstanceInfo::getModelId), subCondition);
            }
        }else if(StringUtils.hasText(instanceSearchParam.getGroupOrModelId())){
            //根据模型或分组id查询实例信息
            SubCondition subCondition = new SubCondition(CriteriaOpsType.in.name(), instanceSearchParam.getGroupOrModelId());
            instanceSearchParam.addSubCondition(CMDBTool.getFieldName(InstanceInfo::getPath), subCondition);
        }

        if (assetStateQuery != null) {
            Map<String, Object> searchData = new HashMap<>();
            if (assetStateQuery.length > 1) {
                searchData.put(assetStateQuery[0], assetStateQuery[1]);
            } else {
                searchData.put(assetStateQuery[0], null);
            }
            instanceSearchParam.setData(searchData);
        }
        //忽略null值注入
        BeanUtil.copyProperties(tableDataParam, instanceSearchParam, CopyOptions.create().setIgnoreNullValue(true));
        //查询资产状态
        instanceSearchParam.setEnableMonitorStatus(true);
        List<Map> ret = new ArrayList<>();
        ViewProcessorManage processorManage = new ViewProcessorManage();

        List<TableHeaderItem> tableHeaderItems = context.getTableHeaderItems();
        //不分页查询
//        //instanceSearchParam.setPage(null);
        instanceInfos = instanceService.aggregateList(instanceSearchParam);

        long time2 = System.currentTimeMillis();
        if (null != instanceInfos && null != tableHeaderItems) {
            Set<RelateDataViewProcessor> relateDataViewProcess = processorManage.buildRelateDataViewProcessor(tableHeaderItems);
            Map<? extends Class<? extends RelateDataViewProcessor>, List<RelateDataViewProcessor>> collect = relateDataViewProcess.stream().collect(Collectors.groupingBy(s -> s.getClass()));
            Set<RelateDataViewProcessor> idsRelateDataViewProcessors = new HashSet<>();
                    collect.forEach((k,v)->{
                if(v!=null && v.size()>0){
                    RelateDataViewProcessor relateDataViewProcessor = v.get(0);
                    idsRelateDataViewProcessors.add(relateDataViewProcessor);
                }
            });


            //初始化
            int seq = 0;
            for (InstanceInfoExtend instanceInfo : instanceInfos) {
                seq++;
                Map data = new LinkedHashMap();
                ret.add(data);
                if (tableDataParam.isShowAllField()) {
                    Map<String, Object> dataMap = instanceInfo.getData();
                    data.putAll(dataMap);
                }
                for (TableHeaderItem item : tableHeaderItems) {
                    Object value = instanceInfo.getValue(item.getField());
                    data.put(item.getField(), value);
                }
                data.put(CMDBTool.getFieldName(InstanceInfoExtend::getModelName),instanceInfo.getModelName());
                data.put(CMDBTool.getFieldName(InstanceInfoExtend::getModelGroupName), instanceInfo.getModelGroupName());
                data.put(CMDBTool.getFieldName(InstanceInfoExtend::getModelId), instanceInfo.getModelId());
                data.put(CMDBTool.getFieldName(InstanceInfoExtend::getFinanceParentId), instanceInfo.getFinanceParentId());
                data.put(CMDBTool.getFieldName(InstanceInfoExtend::getGroupId), instanceInfo.getGroupId());
                //data.put(SEQ, seq);
                if (null == idsRelateDataViewProcessors || idsRelateDataViewProcessors.size() == 0) {
                    continue;
                }
                for (RelateDataViewProcessor processor : idsRelateDataViewProcessors) {
                    processor.init(instanceInfo, data);
                }
            }

            if (null == idsRelateDataViewProcessors || idsRelateDataViewProcessors.size() == 0) {
                return ret;
            }
            //查询外部服务关联数据
            for (RelateDataViewProcessor processor : idsRelateDataViewProcessors) {
                processor.selectRelateData(context);
            }

            //设置关联数据
            for (Map data : ret) {
                for (RelateDataViewProcessor processor : idsRelateDataViewProcessors) {
                    processor.setRelateData(data);
                }
            }
        }
        long time3 = System.currentTimeMillis();

        log.info("实例列表数据数量:"+instanceInfos.size());
        log.info("获取实例列表数据:" + (time2 - time1) + "ms;权限数据转换:" + (time3 - time2) + "ms");
        return ret;
    }

    @Override
    public List<TableHeaderItem> genDefaultTableHeader(Class clazz) throws Exception {
        long time1 = System.currentTimeMillis();
        ModelPropertyServiceImpl modelService = (ModelPropertyServiceImpl) cmdbServiceManage.getModelService(ModelPropertyServiceImpl.ID);
        List<PropertyInfo> commonModelPropertyInfos = modelService.getCommonModelPropertyInfos();

        List<TableHeaderItem> tableHeaderItems = new ArrayList<>();
//        TableHeaderItem seqItem = TableHeaderItem.build().field(SEQ).headerName(SEQName).visible(true);
//        tableHeaderItems.add(seqItem);
        addDefaultTableHeaderItem(tableHeaderItems);
        long time2 = System.currentTimeMillis();

        Map<String, TableHeaderItem> itemMap = new HashMap<>();
        if (null != commonModelPropertyInfos) {
            for (PropertyInfo propertyInfo : commonModelPropertyInfos) {
                Set<FieldViewAuthType> fieldViewAuthTypes = propertyInfo.getFieldViewAuthTypes();

                //只展示list权限的数据
                if (null == fieldViewAuthTypes || !fieldViewAuthTypes.contains(FieldViewAuthType.list)) {
                    continue;
                }

                TableHeaderItem item = null;
                ForeignKey foreignKey = propertyInfo.getForeignKey();
                if (null == foreignKey || !StringUtils.hasText(foreignKey.getKeyName())) {
                    item = new TableHeaderItem();
                } else {
                    RelatedDataType relatedDataType = RelatedDataType.valueOf(foreignKey.getRelatedDataType());
                    item = TableHeaderItemExt.build().keyName(foreignKey.getKeyName());
                    item.setParseType(relatedDataType);
                }

                item.setField(propertyInfo.getId());
                item.setHeaderName(propertyInfo.getName());
                item.setPropertyTypeId(propertyInfo.getPropertyTypeRef().getTypeId());
                boolean visible = propertyInfo.isDefaultListVisible();
                item.setVisible(visible);
                item.setFlex(flexNum);
                itemMap.put(item.getField(), item);
            }

            if (null != tableHeaderSort) {
                for (String key : tableHeaderSort) {
                    TableHeaderItem item = itemMap.get(key);
                    if (null != item) {
                        tableHeaderItems.add(item);
                        itemMap.remove(key);
                    }
                }

                tableHeaderItems.addAll(itemMap.values());
            }
        }
        long time3 = System.currentTimeMillis();
        log.info("TableProcessorCommonInstance::getCommonModelPropertyInfo耗时:" + (time2 - time1) + "ms;TableHeaderItem：" + (time3 - time2) + "ms");
        return tableHeaderItems;
    }

    private void addDefaultTableHeaderItem(List<TableHeaderItem> tableHeaderItems) {
        TableHeaderItem tableHeaderItem = TableHeaderItem.build().field(CMDBDefaultIdKey).headerName(CMDBDefaultIdName).visible(false).flex(100);
        tableHeaderItems.add(tableHeaderItem);
    }
}
